/**
 * @file flip_sse_bswap.c
 *
 * This module deals with flipping discs.
 *
 * A function is provided for each square of the board. These functions are
 * gathered into an array of functions, so that a fast access to each function
 * is allowed. The generic form of the function take as input the player and
 * the opponent bitboards and return the flipped squares into a bitboard.
 *
 * Given the following notation:
 *  - x = square where we play,
 *  - P = player's disc pattern,
 *  - O = opponent's disc pattern,
 * the basic principle is to read into an array the result of a move. Doing
 * this is easier for a single line ; so we can use arrays of the form:
 *  - ARRAY[x][8-bits disc pattern].
 * The problem is thus to convert any line of a 64-bits disc pattern into an
 * 8-bits disc pattern. A fast way to do this is to select the right line,
 * with a bit-mask, to gather the masked-bits into a continuous set by a simple
 * multiplication and to right-shift the result to scale it into a number
 * between 0 and 255.
 * Once we get our 8-bits disc patterns,a first array (OUTFLANK) is used to
 * get the player's discs that surround the opponent discs:
 *  - outflank = OUTFLANK[x][O] & P
 * (Only inner 6-bits of the P are in interest here.)
 * The result is then used as an index to access a second array giving the
 * flipped discs according to the surrounding player's discs:
 *  - flipped = FLIPPED[x][outflank].
 * (Flipped discs fall into inner 6-bits.)
 * Finally, a precomputed array transform the inner 6-bits disc pattern back into a
 * 64-bits disc pattern, and the flipped squares for each line are gathered and
 * returned to generate moves.
 *
 * If the OUTFLANK search is in LSB to MSB direction, carry propagation 
 * can be used to determine contiguous opponent discs.
 * If the OUTFLANK search is in MSB to LSB direction, CONTIG_X tables
 * are used to determine coutiguous opponent discs.
 *
 * @date 1998 - 2014
 * @author Richard Delorme
 * @author Toshihiko Okuhara
 * @version 4.4
 */

#include <x86intrin.h>

/** outflank array (indexed with inner 6 bits) */
static const unsigned char OUTFLANK[64][8] = {
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00 },
	{ 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x10, 0x00, 0x04, 0x00, 0x00, 0x00 },
	{ 0x04, 0x00, 0x11, 0x00, 0x04, 0x00, 0x00, 0x00 },
	{ 0x00, 0x10, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 },
	{ 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x00 },
	{ 0x04, 0x00, 0x01, 0x20, 0x00, 0x08, 0x00, 0x00 },
	{ 0x00, 0x08, 0x00, 0x22, 0x00, 0x08, 0x00, 0x00 },
	{ 0x08, 0x00, 0x00, 0x21, 0x00, 0x08, 0x00, 0x00 },
	{ 0x00, 0x00, 0x20, 0x00, 0x00, 0x04, 0x00, 0x00 },
	{ 0x04, 0x00, 0x21, 0x00, 0x00, 0x04, 0x00, 0x00 },
	{ 0x00, 0x20, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00 },
	{ 0x20, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x10, 0x00 },
	{ 0x04, 0x00, 0x01, 0x00, 0x40, 0x00, 0x10, 0x00 },
	{ 0x00, 0x08, 0x00, 0x02, 0x40, 0x00, 0x10, 0x00 },
	{ 0x08, 0x00, 0x00, 0x01, 0x40, 0x00, 0x10, 0x00 },
	{ 0x00, 0x00, 0x10, 0x00, 0x44, 0x00, 0x10, 0x00 },
	{ 0x04, 0x00, 0x11, 0x00, 0x44, 0x00, 0x10, 0x00 },
	{ 0x00, 0x10, 0x00, 0x00, 0x42, 0x00, 0x10, 0x00 },
	{ 0x10, 0x00, 0x00, 0x00, 0x41, 0x00, 0x10, 0x00 },
	{ 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x08, 0x00 },
	{ 0x04, 0x00, 0x01, 0x40, 0x00, 0x00, 0x08, 0x00 },
	{ 0x00, 0x08, 0x00, 0x42, 0x00, 0x00, 0x08, 0x00 },
	{ 0x08, 0x00, 0x00, 0x41, 0x00, 0x00, 0x08, 0x00 },
	{ 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x04, 0x00 },
	{ 0x04, 0x00, 0x41, 0x00, 0x00, 0x00, 0x04, 0x00 },
	{ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00 },
	{ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x20 },
	{ 0x04, 0x00, 0x01, 0x00, 0x00, 0x80, 0x00, 0x20 },
	{ 0x00, 0x08, 0x00, 0x02, 0x00, 0x80, 0x00, 0x20 },
	{ 0x08, 0x00, 0x00, 0x01, 0x00, 0x80, 0x00, 0x20 },
	{ 0x00, 0x00, 0x10, 0x00, 0x04, 0x80, 0x00, 0x20 },
	{ 0x04, 0x00, 0x11, 0x00, 0x04, 0x80, 0x00, 0x20 },
	{ 0x00, 0x10, 0x00, 0x00, 0x02, 0x80, 0x00, 0x20 },
	{ 0x10, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x20 },
	{ 0x00, 0x00, 0x00, 0x20, 0x00, 0x88, 0x00, 0x20 },
	{ 0x04, 0x00, 0x01, 0x20, 0x00, 0x88, 0x00, 0x20 },
	{ 0x00, 0x08, 0x00, 0x22, 0x00, 0x88, 0x00, 0x20 },
	{ 0x08, 0x00, 0x00, 0x21, 0x00, 0x88, 0x00, 0x20 },
	{ 0x00, 0x00, 0x20, 0x00, 0x00, 0x84, 0x00, 0x20 },
	{ 0x04, 0x00, 0x21, 0x00, 0x00, 0x84, 0x00, 0x20 },
	{ 0x00, 0x20, 0x00, 0x00, 0x00, 0x82, 0x00, 0x20 },
	{ 0x20, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x20 },
	{ 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x10 },
	{ 0x04, 0x00, 0x01, 0x00, 0x80, 0x00, 0x00, 0x10 },
	{ 0x00, 0x08, 0x00, 0x02, 0x80, 0x00, 0x00, 0x10 },
	{ 0x08, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x10 },
	{ 0x00, 0x00, 0x10, 0x00, 0x84, 0x00, 0x00, 0x10 },
	{ 0x04, 0x00, 0x11, 0x00, 0x84, 0x00, 0x00, 0x10 },
	{ 0x00, 0x10, 0x00, 0x00, 0x82, 0x00, 0x00, 0x10 },
	{ 0x10, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x10 },
	{ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x08 },
	{ 0x04, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x08 },
	{ 0x00, 0x08, 0x00, 0x82, 0x00, 0x00, 0x00, 0x08 },
	{ 0x08, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x08 },
	{ 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x04 },
	{ 0x04, 0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x04 },
	{ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 },
	{ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }
};

/** flip array (indexed with outflank) */
static const unsigned char FLIPPED[137][8] = {
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e },
	{ 0x00, 0x00, 0x00, 0x04, 0x0c, 0x1c, 0x3c, 0x7c },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x02, 0x00, 0x00, 0x00, 0x08, 0x18, 0x38, 0x78 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x06, 0x04, 0x00, 0x00, 0x00, 0x10, 0x30, 0x70 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x0e, 0x0c, 0x08, 0x00, 0x00, 0x00, 0x20, 0x60 },
	{ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x1e, 0x1c, 0x18, 0x10, 0x00, 0x00, 0x00, 0x40 },
	{ 0x00, 0x00, 0x1a, 0x16, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x3e, 0x3c, 0x38, 0x30, 0x20, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x3a, 0x36, 0x2e, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x34, 0x2c, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x7e, 0x7c, 0x78, 0x70, 0x60, 0x40, 0x00, 0x00 },
	{ 0x00, 0x00, 0x7a, 0x76, 0x6e, 0x5e, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x74, 0x6c, 0x5c, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x68, 0x58, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00 }
};

static const __v2di mask[3][64] = { {
	{ ~0x0000000000000000ULL, ~0x0000000000000000ULL }, { ~0x0000000000000100ULL, ~0x0000000000000000ULL },
	{ ~0x0000000000010200ULL, ~0x0000000000000000ULL }, { ~0x0000000001020400ULL, ~0x0000000000000000ULL },
	{ ~0x0000000102040800ULL, ~0x0000000000000000ULL }, { ~0x0000010204081000ULL, ~0x0000000000000000ULL },
	{ ~0x0001020408102000ULL, ~0x0000000000000000ULL }, { ~0x0102040810204000ULL, ~0x0000000000000000ULL },
	{ ~0x0000000000000000ULL, ~0x0200000000000000ULL }, { ~0x0000000000010000ULL, ~0x0400000000000000ULL },
	{ ~0x0000000001020000ULL, ~0x0800000000000000ULL }, { ~0x0000000102040000ULL, ~0x1000000000000000ULL },
	{ ~0x0000010204080000ULL, ~0x2000000000000000ULL }, { ~0x0001020408100000ULL, ~0x4000000000000000ULL },
	{ ~0x0102040810200000ULL, ~0x8000000000000000ULL }, { ~0x0204081020400000ULL, ~0x0000000000000000ULL },
	{ ~0x0000000000000000ULL, ~0x0402000000000000ULL }, { ~0x0000000001000000ULL, ~0x0804000000000000ULL },
	{ ~0x0000000102000000ULL, ~0x1008000000000000ULL }, { ~0x0000010204000000ULL, ~0x2010000000000000ULL },
	{ ~0x0001020408000000ULL, ~0x4020000000000000ULL }, { ~0x0102040810000000ULL, ~0x8040000000000000ULL },
	{ ~0x0204081020000000ULL, ~0x0080000000000000ULL }, { ~0x0408102040000000ULL, ~0x0000000000000000ULL },
	{ ~0x0000000000000000ULL, ~0x0804020000000000ULL }, { ~0x0000000100000000ULL, ~0x1008040000000000ULL },
	{ ~0x0000010200000000ULL, ~0x2010080000000000ULL }, { ~0x0001020400000000ULL, ~0x4020100000000000ULL },
	{ ~0x0102040800000000ULL, ~0x8040200000000000ULL }, { ~0x0204081000000000ULL, ~0x0080400000000000ULL },
	{ ~0x0408102000000000ULL, ~0x0000800000000000ULL }, { ~0x0810204000000000ULL, ~0x0000000000000000ULL },
	{ ~0x0000000000000000ULL, ~0x1008040200000000ULL }, { ~0x0000010000000000ULL, ~0x2010080400000000ULL },
	{ ~0x0001020000000000ULL, ~0x4020100800000000ULL }, { ~0x0102040000000000ULL, ~0x8040201000000000ULL },
	{ ~0x0204080000000000ULL, ~0x0080402000000000ULL }, { ~0x0408100000000000ULL, ~0x0000804000000000ULL },
	{ ~0x0810200000000000ULL, ~0x0000008000000000ULL }, { ~0x1020400000000000ULL, ~0x0000000000000000ULL },
	{ ~0x0000000000000000ULL, ~0x2010080402000000ULL }, { ~0x0001000000000000ULL, ~0x4020100804000000ULL },
	{ ~0x0102000000000000ULL, ~0x8040201008000000ULL }, { ~0x0204000000000000ULL, ~0x0080402010000000ULL },
	{ ~0x0408000000000000ULL, ~0x0000804020000000ULL }, { ~0x0810000000000000ULL, ~0x0000008040000000ULL },
	{ ~0x1020000000000000ULL, ~0x0000000080000000ULL }, { ~0x2040000000000000ULL, ~0x0000000000000000ULL },
	{ ~0x0000000000000000ULL, ~0x4020100804020000ULL }, { ~0x0100000000000000ULL, ~0x8040201008040000ULL },
	{ ~0x0200000000000000ULL, ~0x0080402010080000ULL }, { ~0x0400000000000000ULL, ~0x0000804020100000ULL },
	{ ~0x0800000000000000ULL, ~0x0000008040200000ULL }, { ~0x1000000000000000ULL, ~0x0000000080400000ULL },
	{ ~0x2000000000000000ULL, ~0x0000000000800000ULL }, { ~0x4000000000000000ULL, ~0x0000000000000000ULL },
	{ ~0x0000000000000000ULL, ~0x8040201008040200ULL }, { ~0x0000000000000000ULL, ~0x0080402010080400ULL },
	{ ~0x0000000000000000ULL, ~0x0000804020100800ULL }, { ~0x0000000000000000ULL, ~0x0000008040201000ULL },
	{ ~0x0000000000000000ULL, ~0x0000000080402000ULL }, { ~0x0000000000000000ULL, ~0x0000000000804000ULL },
	{ ~0x0000000000000000ULL, ~0x0000000000008000ULL }, { ~0x0000000000000000ULL, ~0x0000000000000000ULL }
}, {
	{ ~0x0101010101010100ULL, ~0x0000000000000000ULL }, { ~0x0202020202020200ULL, ~0x0000000000000000ULL },
	{ ~0x0404040404040400ULL, ~0x0000000000000000ULL }, { ~0x0808080808080800ULL, ~0x0000000000000000ULL },
	{ ~0x1010101010101000ULL, ~0x0000000000000000ULL }, { ~0x2020202020202000ULL, ~0x0000000000000000ULL },
	{ ~0x4040404040404000ULL, ~0x0000000000000000ULL }, { ~0x8080808080808000ULL, ~0x0000000000000000ULL },
	{ ~0x0101010101010000ULL, ~0x0100000000000000ULL }, { ~0x0202020202020000ULL, ~0x0200000000000000ULL },
	{ ~0x0404040404040000ULL, ~0x0400000000000000ULL }, { ~0x0808080808080000ULL, ~0x0800000000000000ULL },
	{ ~0x1010101010100000ULL, ~0x1000000000000000ULL }, { ~0x2020202020200000ULL, ~0x2000000000000000ULL },
	{ ~0x4040404040400000ULL, ~0x4000000000000000ULL }, { ~0x8080808080800000ULL, ~0x8000000000000000ULL },
	{ ~0x0101010101000000ULL, ~0x0101000000000000ULL }, { ~0x0202020202000000ULL, ~0x0202000000000000ULL },
	{ ~0x0404040404000000ULL, ~0x0404000000000000ULL }, { ~0x0808080808000000ULL, ~0x0808000000000000ULL },
	{ ~0x1010101010000000ULL, ~0x1010000000000000ULL }, { ~0x2020202020000000ULL, ~0x2020000000000000ULL },
	{ ~0x4040404040000000ULL, ~0x4040000000000000ULL }, { ~0x8080808080000000ULL, ~0x8080000000000000ULL },
	{ ~0x0101010100000000ULL, ~0x0101010000000000ULL }, { ~0x0202020200000000ULL, ~0x0202020000000000ULL },
	{ ~0x0404040400000000ULL, ~0x0404040000000000ULL }, { ~0x0808080800000000ULL, ~0x0808080000000000ULL },
	{ ~0x1010101000000000ULL, ~0x1010100000000000ULL }, { ~0x2020202000000000ULL, ~0x2020200000000000ULL },
	{ ~0x4040404000000000ULL, ~0x4040400000000000ULL }, { ~0x8080808000000000ULL, ~0x8080800000000000ULL },
	{ ~0x0101010000000000ULL, ~0x0101010100000000ULL }, { ~0x0202020000000000ULL, ~0x0202020200000000ULL },
	{ ~0x0404040000000000ULL, ~0x0404040400000000ULL }, { ~0x0808080000000000ULL, ~0x0808080800000000ULL },
	{ ~0x1010100000000000ULL, ~0x1010101000000000ULL }, { ~0x2020200000000000ULL, ~0x2020202000000000ULL },
	{ ~0x4040400000000000ULL, ~0x4040404000000000ULL }, { ~0x8080800000000000ULL, ~0x8080808000000000ULL },
	{ ~0x0101000000000000ULL, ~0x0101010101000000ULL }, { ~0x0202000000000000ULL, ~0x0202020202000000ULL },
	{ ~0x0404000000000000ULL, ~0x0404040404000000ULL }, { ~0x0808000000000000ULL, ~0x0808080808000000ULL },
	{ ~0x1010000000000000ULL, ~0x1010101010000000ULL }, { ~0x2020000000000000ULL, ~0x2020202020000000ULL },
	{ ~0x4040000000000000ULL, ~0x4040404040000000ULL }, { ~0x8080000000000000ULL, ~0x8080808080000000ULL },
	{ ~0x0100000000000000ULL, ~0x0101010101010000ULL }, { ~0x0200000000000000ULL, ~0x0202020202020000ULL },
	{ ~0x0400000000000000ULL, ~0x0404040404040000ULL }, { ~0x0800000000000000ULL, ~0x0808080808080000ULL },
	{ ~0x1000000000000000ULL, ~0x1010101010100000ULL }, { ~0x2000000000000000ULL, ~0x2020202020200000ULL },
	{ ~0x4000000000000000ULL, ~0x4040404040400000ULL }, { ~0x8000000000000000ULL, ~0x8080808080800000ULL },
	{ ~0x0000000000000000ULL, ~0x0101010101010100ULL }, { ~0x0000000000000000ULL, ~0x0202020202020200ULL },
	{ ~0x0000000000000000ULL, ~0x0404040404040400ULL }, { ~0x0000000000000000ULL, ~0x0808080808080800ULL },
	{ ~0x0000000000000000ULL, ~0x1010101010101000ULL }, { ~0x0000000000000000ULL, ~0x2020202020202000ULL },
	{ ~0x0000000000000000ULL, ~0x4040404040404000ULL }, { ~0x0000000000000000ULL, ~0x8080808080808000ULL }
}, {
	{ ~0x8040201008040200ULL, ~0x0000000000000000ULL }, { ~0x0080402010080400ULL, ~0x0000000000000000ULL },
	{ ~0x0000804020100800ULL, ~0x0000000000000000ULL }, { ~0x0000008040201000ULL, ~0x0000000000000000ULL },
	{ ~0x0000000080402000ULL, ~0x0000000000000000ULL }, { ~0x0000000000804000ULL, ~0x0000000000000000ULL },
	{ ~0x0000000000008000ULL, ~0x0000000000000000ULL }, { ~0x0000000000000000ULL, ~0x0000000000000000ULL },
	{ ~0x4020100804020000ULL, ~0x0000000000000000ULL }, { ~0x8040201008040000ULL, ~0x0100000000000000ULL },
	{ ~0x0080402010080000ULL, ~0x0200000000000000ULL }, { ~0x0000804020100000ULL, ~0x0400000000000000ULL },
	{ ~0x0000008040200000ULL, ~0x0800000000000000ULL }, { ~0x0000000080400000ULL, ~0x1000000000000000ULL },
	{ ~0x0000000000800000ULL, ~0x2000000000000000ULL }, { ~0x0000000000000000ULL, ~0x4000000000000000ULL },
	{ ~0x2010080402000000ULL, ~0x0000000000000000ULL }, { ~0x4020100804000000ULL, ~0x0001000000000000ULL },
	{ ~0x8040201008000000ULL, ~0x0102000000000000ULL }, { ~0x0080402010000000ULL, ~0x0204000000000000ULL },
	{ ~0x0000804020000000ULL, ~0x0408000000000000ULL }, { ~0x0000008040000000ULL, ~0x0810000000000000ULL },
	{ ~0x0000000080000000ULL, ~0x1020000000000000ULL }, { ~0x0000000000000000ULL, ~0x2040000000000000ULL },
	{ ~0x1008040200000000ULL, ~0x0000000000000000ULL }, { ~0x2010080400000000ULL, ~0x0000010000000000ULL },
	{ ~0x4020100800000000ULL, ~0x0001020000000000ULL }, { ~0x8040201000000000ULL, ~0x0102040000000000ULL },
	{ ~0x0080402000000000ULL, ~0x0204080000000000ULL }, { ~0x0000804000000000ULL, ~0x0408100000000000ULL },
	{ ~0x0000008000000000ULL, ~0x0810200000000000ULL }, { ~0x0000000000000000ULL, ~0x1020400000000000ULL },
	{ ~0x0804020000000000ULL, ~0x0000000000000000ULL }, { ~0x1008040000000000ULL, ~0x0000000100000000ULL },
	{ ~0x2010080000000000ULL, ~0x0000010200000000ULL }, { ~0x4020100000000000ULL, ~0x0001020400000000ULL },
	{ ~0x8040200000000000ULL, ~0x0102040800000000ULL }, { ~0x0080400000000000ULL, ~0x0204081000000000ULL },
	{ ~0x0000800000000000ULL, ~0x0408102000000000ULL }, { ~0x0000000000000000ULL, ~0x0810204000000000ULL },
	{ ~0x0402000000000000ULL, ~0x0000000000000000ULL }, { ~0x0804000000000000ULL, ~0x0000000001000000ULL },
	{ ~0x1008000000000000ULL, ~0x0000000102000000ULL }, { ~0x2010000000000000ULL, ~0x0000010204000000ULL },
	{ ~0x4020000000000000ULL, ~0x0001020408000000ULL }, { ~0x8040000000000000ULL, ~0x0102040810000000ULL },
	{ ~0x0080000000000000ULL, ~0x0204081020000000ULL }, { ~0x0000000000000000ULL, ~0x0408102040000000ULL },
	{ ~0x0200000000000000ULL, ~0x0000000000000000ULL }, { ~0x0400000000000000ULL, ~0x0000000000010000ULL },
	{ ~0x0800000000000000ULL, ~0x0000000001020000ULL }, { ~0x1000000000000000ULL, ~0x0000000102040000ULL },
	{ ~0x2000000000000000ULL, ~0x0000010204080000ULL }, { ~0x4000000000000000ULL, ~0x0001020408100000ULL },
	{ ~0x8000000000000000ULL, ~0x0102040810200000ULL }, { ~0x0000000000000000ULL, ~0x0204081020400000ULL },
	{ ~0x0000000000000000ULL, ~0x0000000000000000ULL }, { ~0x0000000000000000ULL, ~0x0000000000000100ULL },
	{ ~0x0000000000000000ULL, ~0x0000000000010200ULL }, { ~0x0000000000000000ULL, ~0x0000000001020400ULL },
	{ ~0x0000000000000000ULL, ~0x0000000102040800ULL }, { ~0x0000000000000000ULL, ~0x0000010204081000ULL },
	{ ~0x0000000000000000ULL, ~0x0001020408102000ULL }, { ~0x0000000000000000ULL, ~0x0102040810204000ULL }
} };

#define	SWAP64	0x4e	// for _mm_shuffle_epi32
#define	SWAP32	0xb1

/**
 * Make inverted flip mask if opponent's disc are surrounded by player's.
 *
 * -1 if outflank is 0
 *  0 if a 1 is in 64 bit
 */
static inline __v2di flipmask (__v2di outflank) {
	return _mm_cmpeq_epi32(_mm_shuffle_epi32(outflank, SWAP32), outflank);
}

/**
 * Compute flipped discs when playing on square pos.
 *
 * @param pos player's move.
 * @param P player's disc pattern.
 * @param O opponent's disc pattern.
 * @return flipped disc pattern.
 */

unsigned long long flip(int pos, const unsigned long long P, const unsigned long long O)
{
	__v2di	outflank7, outflank8, outflank9, PP, OO;
	int	x, y8, index_h;
	unsigned long long	flipped;
	static const __v2di minusone = { -1LL, -1LL };

	if (pos >= 64)	// pass
		return 0;

#ifdef __x86_64__
	PP = _mm_set_epi64x(__builtin_bswap64(P), P);
	OO = _mm_set_epi64x(__builtin_bswap64(O), O);
#else
	PP = _mm_set_epi32(__builtin_bswap32(P), __builtin_bswap32(P >> 32), (P >> 32), P);
	OO = _mm_set_epi32(__builtin_bswap32(O), __builtin_bswap32(O >> 32), (O >> 32), O);
#endif

#if (defined (USE_GAS_X64) || defined(USE_GAS_X86)) && !defined(__AVX__)
	__asm__ (
						"movdqa	%4, %1\n\t"		"movdqa	%4, %2\n\t"
		"movdqa	(%5), %0\n\t"		"movdqa	1024(%5), %%xmm3\n\t"	"movdqa	2048(%5), %%xmm5\n\t"
		"por	%0, %4\n\t"		"por	%%xmm3, %1\n\t"		"por	%%xmm5, %2\n\t"
		"psubq	%6, %4\n\t"		"psubq	%6, %1\n\t"		"psubq	%6, %2\n\t"
		"pand	%3, %4\n\t"		"pand	%3, %1\n\t"		"pand	%3, %2\n\t"
		"movdqa	%0, %3\n\t"
		"pandn	%4, %3\n\t"		"pandn	%1, %%xmm3\n\t"		"pandn	%2, %%xmm5\n\t"
		"pshufd	$177, %3, %4\n\t"	"pshufd	$177, %%xmm3, %1\n\t"	"pshufd	$177, %%xmm5, %2\n\t"
		"pcmpeqd %3, %4\n\t"		"pcmpeqd %%xmm3, %1\n\t"	"pcmpeqd %%xmm5, %2\n\t"
		"paddq	%6, %3\n\t"		"paddq	%6, %%xmm3\n\t"		"paddq	%6, %%xmm5\n\t"
		"psubq	%4, %3\n\t"		"psubq	%1, %%xmm3\n\t"		"psubq	%2, %%xmm5\n\t"
						"movdqa	1024(%5), %1\n\t"	"movdqa	2048(%5), %2\n\t"
		"pandn	%3, %0\n\t"		"pandn	%%xmm3, %1\n\t"		"pandn	%%xmm5, %2\n\t"
						"por	%1, %0\n\t"		"por	%2, %0"
	: "=&x" (outflank7), "=&x" (outflank8), "=&x" (outflank9)
	: "x" (PP), "x" (OO), "r" (&mask[0][pos]), "xm" (minusone)
	: "xmm3", "xmm5");

#else
	outflank7 = _mm_andnot_si128(mask[0][pos], ((OO | mask[0][pos]) - minusone) & PP);
	outflank8 = _mm_andnot_si128(mask[1][pos], ((OO | mask[1][pos]) - minusone) & PP);
	outflank9 = _mm_andnot_si128(mask[2][pos], ((OO | mask[2][pos]) - minusone) & PP);
	outflank7 = _mm_andnot_si128(mask[0][pos], outflank7 - (flipmask(outflank7) - minusone));
	outflank8 = _mm_andnot_si128(mask[1][pos], outflank8 - (flipmask(outflank8) - minusone));
	outflank9 = _mm_andnot_si128(mask[2][pos], outflank9 - (flipmask(outflank9) - minusone));
	outflank7 = outflank7 | outflank8 | outflank9;
#endif
	flipped = outflank7[0] | __builtin_bswap64(outflank7[1]);

	x = pos & 7;
	y8 = pos & 0x38;
	index_h = OUTFLANK[((unsigned int) (O >> y8) & 0x7E) >> 1][x] & (P >> y8);
	flipped |= ((unsigned long long) FLIPPED[index_h][x]) << y8;

	return flipped;
}
